package com.broker.base.auth;


import io.jsonwebtoken.*;
import lombok.Data;
import lombok.experimental.Accessors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

@Accessors(chain = true)
@Data
public class TokenProvider {

    private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
    private String secretKey = "";
    private long tokenValidityInMilliseconds = 7*24*60*1000;

    public TokenProvider(){
        this.secretKey = System.getProperty("broker.auth.signingkey", "");
        this.tokenValidityInMilliseconds = Long.parseLong(System.getProperty("broker.auth.tokenvalid", "10080000"));
    }


    public String createToken(UserJwt userJwt) {
        Date validity = createValidity();
        return Jwts.builder()
                .setSubject("userJwt")
                .claim(UserJwt.APP_KEY, userJwt.getAppKey())
                .claim(UserJwt.USER_AUID, userJwt.getAuid())
                .signWith(SignatureAlgorithm.HS512, this.secretKey)
                .setExpiration(validity)
                .compact();
    }

    public String createToken(SDKJwt sdkJwt) {
        Date validity = createValidity();
        return Jwts.builder()
                .setSubject("sdkJwt")
                .claim(SDKJwt.APP_KEY, sdkJwt.getAppKey())
                .claim(SDKJwt.APP_SECRET, sdkJwt.getAppSecret())
                .signWith(SignatureAlgorithm.HS512, this.secretKey)
                .setExpiration(validity)
                .compact();
    }

    public String createToken(SDKUserJwt sdkUserJwt) {
        Date validity = createValidity();
        return Jwts.builder()
                .setSubject("sdkUserJwt")
                .claim(SDKUserJwt.SDK_UID, sdkUserJwt.getSdkUid())
                .claim(SDKUserJwt.NAME, sdkUserJwt.getName())
                .claim(SDKUserJwt.ROLE, sdkUserJwt.getRole())
                .signWith(SignatureAlgorithm.HS512, this.secretKey)
                .setExpiration(validity)
                .compact();
    }



    private Date createValidity(){
        long now = (new Date()).getTime();
        Date validity = new Date(now + tokenValidityInMilliseconds);
        return validity;
    }

    public UserJwt getUserJwt(String token) {
        if(validateToken(token).getCode() != 0){
            return new UserJwt();
        }
        Claims claims = Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody();
        return new UserJwt()
                .setAppKey((String)claims.get(UserJwt.APP_KEY))
                .setAuid((String)claims.get(UserJwt.USER_AUID))
                ;
    }


    public SDKJwt getSDKJwt(String token) {
        if(validateToken(token).getCode() != 0){
            return new SDKJwt();
        }
        Claims claims = Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody();
        return new SDKJwt()
                .setAppKey((String)claims.get(SDKJwt.APP_KEY))
                .setAppSecret((String)claims.get(SDKJwt.APP_SECRET))
                ;
    }

    public SDKUserJwt getSDKUserJwt(String token) {
        if(validateToken(token).getCode() != 0){
            return new SDKUserJwt();
        }
        Claims claims = Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(token)
                .getBody();
        return new SDKUserJwt()
                .setSdkUid((String)claims.get(SDKUserJwt.SDK_UID))
                .setName((String)claims.get(SDKUserJwt.NAME))
                .setRole((String)claims.get(SDKUserJwt.ROLE))
                ;
    }



    public TokenStatus validateToken(String authToken) {
        TokenStatus status = new TokenStatus().setCode(0).setErrorMsg("");
        try {
            Jwts.parser().setSigningKey(secretKey).parseClaimsJws(authToken);
            return new TokenStatus().setCode(0).setErrorMsg("");
        } catch (SignatureException e) {
            log.error("Invalid JWT signature trace", e);
            status.setCode(TokenStatus.ERROR_CODE_INVALID_TOKEN)
                    .setErrorMsg("Invalid JWT signature.");
        } catch (MalformedJwtException e) {
            log.error("Invalid JWT token trace", e);
            status.setCode(TokenStatus.ERROR_CODE_INVALID_TOKEN)
                    .setErrorMsg("Invalid JWT signature.");
        } catch (ExpiredJwtException e) {
            log.error("Expired JWT token trace", e);
            status.setCode(TokenStatus.ERROR_CODE_TOKEN_EXPIRE)
                    .setErrorMsg(" Expired JWT token.");
        } catch (UnsupportedJwtException e) {
            log.error("Unsupported JWT token trace", e);
            status.setCode(TokenStatus.ERROR_CODE_INVALID_TOKEN)
                    .setErrorMsg("Invalid JWT signature.");
        } catch (IllegalArgumentException e) {
            log.error("JWT token compact of handler are invalid trace", e);
            status.setCode(TokenStatus.ERROR_CODE_INVALID_TOKEN)
                    .setErrorMsg("Invalid JWT signature.");
        }


        return status;
    }

}
